/********************************************
 *
 *	File: 		operations.c
 *	Name: 		Rob King
 *	Project:	Project 2
 *
 ********************************************/

#include "glob.h"
#include "virtualmem.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "sharedmem.h"
#include "freeMem.h"
#include "memory.h"

char* readFail = "Memory read failure.";
char* writeFail = "Memory write failure.";

void itob(int n, char * s);
size_t atob(bop op1, bop op2);

void LoadRegister(VMEMMOD* vm, size_t memLocation) {
	/* R := [a] */
	int err;
	err = vmem_read(vm, memLocation, (vm->mm->pcb[vm->mm->nCurrProc - 1].reg),
					vm->mm->nCurrProc);

	if (err < 0) {
		printf("%s\n", readFail);
		exit(EXIT_FAILURE);
	}
}

void LoadLow(VMEMMOD* vm, size_t memLocation) {
	/* R := zz[a,3][a,4] */
	char fromMem[4];

	int err = vmem_read(vm, memLocation, fromMem, vm->mm->nCurrProc);

	if (err < 0) {
		printf("%s\n", readFail);
		exit(EXIT_FAILURE);
	}

	vm->mm->pcb[vm->mm->nCurrProc - 1].reg[1] = fromMem[1];
	vm->mm->pcb[vm->mm->nCurrProc - 1].reg[0] = fromMem[0];
}

void LoadHigh(VMEMMOD* vm, size_t memLocation) {
	/* R := [a,1][a,2]zz */
	char fromMem[4];

	int err = vmem_read(vm, memLocation, fromMem, vm->mm->nCurrProc);
	if (err < 0) {
		printf("%s\n", readFail);
		exit(EXIT_FAILURE);
	}

	vm->mm->pcb[vm->mm->nCurrProc - 1].reg[0] = fromMem[0];
	vm->mm->pcb[vm->mm->nCurrProc - 1].reg[1] = fromMem[1];
}

void StoreRegister(VMEMMOD* vm, size_t memLocation) {
	/* [a] := R */
	int err;
	err = vmem_store(vm, memLocation, (vm->mm->pcb[vm->mm->nCurrProc - 1].reg),
			vm->mm->nCurrProc);
	if (err < 0) {
		printf("%s\n", writeFail);
		exit(EXIT_FAILURE);
	}

}

void SetStackPointer(VMEMMOD* vm, size_t memLocation) {
	/* SP := R */
	char x[4] = "0000";
	diss(disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].reg), x);
	memcpy(vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr, x, 4 * sizeof(char));
}

void StoreStackPointer(VMEMMOD* vm) {
	/* R:= SP */
	memcpy(vm->mm->pcb[vm->mm->nCurrProc - 1].reg, vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr, 4
			* sizeof(char));
}

void PushStack(VMEMMOD* vm) {
	/* SP++; [SP]:= R */
	int err;
	char x[4] = "0000";
	diss((disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr) + 1), x);
	memcpy(vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr, x, 4 * sizeof(char));

	/* CRITICAL TODO: THE STACK POINTER IS ALREADY OFFSET SO IT WILL BE OFFSET AGAIN IN MEM_STORE */
	err = vmem_store(vm, disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr),
			(vm->mm->pcb[vm->mm->nCurrProc - 1].reg), vm->mm->nCurrProc);
	if (err < 0) {
		printf("%s\n", writeFail);
		exit(EXIT_FAILURE);
	}
}

void PopStack(VMEMMOD* vm) {
	/* R:=[SP]; SP-- */
	int err;
	char x[4] = "0000";

	/* CRITICAL TODO: The stack pointer is already offset so it will be offset again in mem_read */
	err = vmem_read(vm, disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr),
			(vm->mm->pcb[vm->mm->nCurrProc - 1].reg), vm->mm->nCurrProc); //read memory and put data in temp.
	if (err < 0) {
		printf("%s\n", readFail);
		exit(EXIT_FAILURE);
	}
	diss((disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr) - 1), x);
	memcpy(vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr, x, 4 * sizeof(char));
}

void CompareEqual(VMEMMOD* vm, size_t memLocation) {
	/* if R = [a] then C := 'T' else C := 'F' */
	char temp[4];
	int err;
	err = vmem_read(vm, memLocation, temp, vm->mm->nCurrProc); //read memory and put data in temp.
	if (err < 0) {
		printf("%s\n", readFail);
		exit(EXIT_FAILURE);
	}
	if (!strncmp(vm->mm->pcb[vm->mm->nCurrProc - 1].reg, temp, 4)) //compare register value with what is in memory.
		(vm->mm->pcb[vm->mm->nCurrProc - 1].cFlag) = TRUE;
	else
		(vm->mm->pcb[vm->mm->nCurrProc - 1].cFlag) = FALSE;
}

void CompareLessThan(VMEMMOD* vm, size_t memLocation) {
	/* if R < [a] then C := 'T' else C := 'F' */
	int err;
	char temp[4];
	err = vmem_read(vm, memLocation, temp, vm->mm->nCurrProc); //read memory and put data in temp.
	if (err < 0) {
		printf("%s\n", readFail);
		exit(EXIT_FAILURE);
	}
	if (disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].reg) < disasm(temp)) //compare register with value in memory.
		(vm->mm->pcb[vm->mm->nCurrProc - 1].cFlag) = TRUE;
	else
		(vm->mm->pcb[vm->mm->nCurrProc - 1].cFlag) = FALSE;

}

void BranchConditional(VMEMMOD* vm, size_t memLocation) {
	/* if C = 'T' then IC := a */
	if ((vm->mm->pcb[vm->mm->nCurrProc - 1].cFlag) == TRUE) {
		char temp[5] = { 0 };
		diss(disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].baseReg) + memLocation, temp);
		memcpy((vm->mm->pcb[vm->mm->nCurrProc - 1]).IC, temp, 4 * sizeof(char)); //point IC to the location in memory.
	}
}

void BranchUnconditional(VMEMMOD* vm, size_t memLocation) {
	/* IC := a */
	char temp[5] = { 0 };
	diss(disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].baseReg) + memLocation, temp);
	memcpy((vm->mm->pcb[vm->mm->nCurrProc - 1]).IC, temp, 4 * sizeof(char)); //point IC to the location in memory.
}

void GetData(VMEMMOD* vm, size_t memLocation) {
	/* Read( [b+i], I = 0,...,9) */
	int i;
	char tempstr[4];
	char buffer[50] = { 0 };
	fgets(buffer, 51, vm->mm->pcb[vm->mm->nCurrProc - 1].fpBrain);

	for (i = 0; i < 10; i++) {
		/*tempstr[0] = buffer[(i * 4)];
		 tempstr[1] = buffer[(i * 4) + 1];
		 tempstr[2] = buffer[(i * 4) + 2];
		 tempstr[3] = buffer[(i * 4) + 3];*/
		memcpy(tempstr, &buffer[(i * 4)], 4);
		vmem_store(vm, memLocation, tempstr, vm->mm->nCurrProc);
		memLocation++;
		/*memcpy(&temp, &buffer[i * 4], 4);
		 mem_store(memLocation, temp);
		 memLocation++;*/
	}
}

void PutData(VMEMMOD* vm, size_t memLocation) {
	/* Read( [b+i], I = 0,...,9) */
	int err;
	char temp[4] = { 0 };
	char outgoing[5] = { 0 };
	int i = 0;
	/* Print the process number that it was received from */

	//printf("From %d:\t", disasm(mm->pcb[mm->nCurrProc - 1].reg));

	printf("From %d:\t ", disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].reg));

	for (i = 0; i < 10; i++) {
		err = vmem_read(vm, memLocation, temp, vm->mm->nCurrProc);
		if (err < 0) {
			printf("Memory read failure.\n");
			printf("Current Process: %d Mem Location: %d\n", vm->mm->nCurrProc, memLocation);
			exit(EXIT_FAILURE);
		}

		outgoing[0] = temp[0];
		outgoing[1] = temp[1];
		outgoing[2] = temp[2];
		outgoing[3] = temp[3];
		outgoing[4] = '\0';

		printf("%s ", outgoing);
		memLocation++;
	}
	printf("\n");
	fflush(stdout);
}

void Add(VMEMMOD* vm, size_t memLocation) {
	/* R := R + [a] */
	int err;
	int toAdd;
	int regVal;
	char x[4] = "0000";
	char temp[4];
	err = vmem_read(vm, memLocation, temp, vm->mm->nCurrProc); //get memory at location 'a'.
	if (err < 0) {
		printf("%s\n", readFail);
		exit(EXIT_FAILURE);
	}

	regVal = disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].reg);
	toAdd = disasm(temp);

	regVal = regVal + toAdd;

	if (regVal > 9999)
		regVal = regVal - 10000;

	diss(regVal, x);

	memcpy((vm->mm->pcb[vm->mm->nCurrProc - 1].reg), x, 4 * sizeof(char));
}

void Subtract(VMEMMOD* vm, size_t memLocation) {
	/* R := R - [a], R >= [a] */
	int err;
	int toSub;
	int regVal;
	char x[4] = "0000";
	char temp[4];
	err = vmem_read(vm, memLocation, temp, vm->mm->nCurrProc);
	if (err < 0) {
		printf("%s\n", readFail);
		exit(EXIT_FAILURE);
	}

	regVal = disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].reg);
	toSub = disasm(temp);

	if (regVal < toSub)
		regVal = 0;
	else
		regVal -= toSub;

	diss(regVal, x);

	memcpy((vm->mm->pcb[vm->mm->nCurrProc - 1].reg), x, 4 * sizeof(char));
}

void Multiply(VMEMMOD* vm, size_t memLocation) {
	/* R := R * [a] */
	int err;
	int regVal;
	int toMul;
	char x[4] = "0000";
	char temp[4];
	err = vmem_read(vm, memLocation, temp, vm->mm->nCurrProc);
	if (err < 0) {
		printf("%s\n", readFail);
		exit(EXIT_FAILURE);
	}

	regVal = disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].reg);
	toMul = disasm(temp);

	regVal = (regVal * toMul);

	while (regVal >= 10000) //overflow.
		regVal = regVal - 10000; //subtract until overflow is gone.

	diss(regVal, x);

	memcpy((vm->mm->pcb[vm->mm->nCurrProc - 1].reg), x, 4 * sizeof(char));
}

void Divide(VMEMMOD* vm, size_t memLocation) {
	/* R := R / [a], [a] > 0 */
	int err;
	int regVal;
	int toDiv;
	char x[4] = "0000";
	char temp[4];
	err = vmem_read(vm, memLocation, temp, vm->mm->nCurrProc);
	if (err < 0) {
		printf("%s\n", writeFail);
		exit(EXIT_FAILURE);
	}

	regVal = disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].reg);
	toDiv = disasm(temp);

	if (toDiv == 0)
		regVal = 0;
	else
		regVal = (regVal / toDiv);

	diss(regVal, x);

	memcpy((vm->mm->pcb[vm->mm->nCurrProc - 1].reg), x, 4 * sizeof(char));
}

void PrepStack(VMEMMOD* vm, int *newTop, int *oldTop) {
	/* Temp := [SP] ; SP-- ; [SP] := [SP] - Temp */
	char x[4] = "0000";
	char temp[4] = { 0 };
	int err;

	/* CRITICAL TODO: see previous */
	err = vmem_read(vm, disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr), temp,
			vm->mm->nCurrProc);
	if (err < 0) {
		printf("%s\n", readFail);
		exit(EXIT_FAILURE);
	}
	*oldTop = disasm(temp);

	diss((disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr) - 1), x);
	memcpy(vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr, x, 4);
	err = vmem_read(vm, disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr), temp,
			vm->mm->nCurrProc - 1); //read memory and put data in temp.
	if (err < 0) {
		printf("%s\n", readFail);
		exit(EXIT_FAILURE);
	}

	*newTop = disasm(temp);

}

void CleanStack(VMEMMOD* vm, int newTop) {
	int err;
	char x[4] = "0000";
	diss(newTop, x);

	/* CRITICAL TODO: see previous */
	err = vmem_store(vm, disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].stackPtr), x,
			vm->mm->nCurrProc);
	if (err < 0) {
		printf("%s\n", writeFail);
		exit(EXIT_FAILURE);
	}
}

void AddStack(VMEMMOD* vm) {
	/* Temp := [SP] ; SP-- ; [SP] := [SP] + Temp */
	int oldTop, newTop;

	PrepStack(vm, &newTop, &oldTop);

	newTop = (newTop + oldTop);

	if (newTop > 9999)
		newTop = newTop - 10000;

	CleanStack(vm, newTop);
}

void SubtractStack(VMEMMOD* vm) {
	int newTop, oldTop;
	PrepStack(vm, &newTop, &oldTop);

	if (newTop < 0)
		newTop = 0;

	newTop = (newTop - oldTop);
	CleanStack(vm, newTop);
}

void MultiplyStack(VMEMMOD* vm) {
	/* Temp := [SP] ; SP-- ; [SP] := [SP] * Temp */
	int oldTop, newTop;

	PrepStack(vm, &newTop, &oldTop);

	newTop = (newTop * oldTop);

	while (newTop > 9999)
		newTop = newTop - 10000;

	CleanStack(vm, newTop);

}

void DivideStack(VMEMMOD* vm) {
	/* Temp := [SP] ; SP- - ; [SP] := [SP] / Temp */
	int oldTop, newTop;

	PrepStack(vm, &newTop, &oldTop);

	if (oldTop == 0)
		newTop = 0;
	else
		newTop = (newTop / oldTop);

	CleanStack(vm, newTop);
}

void NoOp(VMEMMOD* vm) {
	/* Null operation */
	usleep(10); //do nothing but wait ten microseconds.
}

void Halt(VMEMMOD* vm) {
	int nCur = vm->mm->nCurrProc - 1;
	int i= 0;
	int numPages = getNumPages(vm, vm->mm->nCurrProc);
	int basepageaddr = -1;

	DISKNODE dn;
	getPidPage(vm->mm->usedDisk, &dn,nCur + 1);

	/* Deallocate the space used by this process */
	addNode(vm->mm->freeDisk,dn.base,dn.end);
	removeDNode(vm->mm->usedDisk, nCur+1);

	for (i = 0; i < numPages; i++) {
		basepageaddr = vm->mm->pcb[nCur].pagetable->pnPageAddr[i]/PAGESIZE;
		addNode(vm->mm->freeMem, basepageaddr, basepageaddr);
	}

	/* Clean up the current process PCB ONLY */
	free(vm->mm->pcb[nCur].reg);
	vm->mm->pcb[nCur].reg = NULL;
	free(vm->mm->pcb[nCur].stackPtr);
	vm->mm->pcb[nCur].stackPtr = NULL;
	free(vm->mm->pcb[nCur].baseReg);
	vm->mm->pcb[nCur].baseReg = NULL;
	free(vm->mm->pcb[nCur].limitReg);
	vm->mm->pcb[nCur].limitReg = NULL;
	//free(mm->pcb[nCur].cFlag);
	free(vm->mm->pcb[nCur].IC);
	vm->mm->pcb[nCur].IC = NULL;
	//free(&(mm->pcb[nCur])); TODO: free all PCBs at once at finish
	//(mm->pcb[nCur]) = NULL;
}

/* Message Functions */
void SendMess(VMEMMOD* vm, u_int16_t nToProc) {
	int i = 0, nStartAddr = 0;
	char temp[4] = { 0 };
	char msg[40] = { 0 };

	/* Place the message into the receiving processes message queue */
	//if((nToProc >= mm->numProgs)){
	//	printf("Invalid Process ID for SendMess()");
	//	return;
	//}

	nStartAddr = disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].reg);

	for (i = 0; i < 10; i++) {
		vmem_read(vm, nStartAddr + i, temp, vm->mm->nCurrProc);
		memcpy(&(msg[i * 4]), temp, 4);
	}

	mEnqueue(vm->mm->pcb[nToProc - 1].msgq, vm->mm->nCurrProc, msg);
}

int ReceiveMess(VMEMMOD* vm, u_int16_t nFromProc) {
	int ret = -1, i = 0;
	int nStartAddr = disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].reg);
	char msg[40] = { 0 };
	char temp[4] = { 0 };
	char bLoadAny = 0;

	/* Dequeue the message from this processes message queue */
	if (nFromProc != 0x5858) {
		char temp[4] = { 0 };
		temp[0] = '0';
		temp[1] = '0';
		temp[2] = ((nFromProc >> 8) & 0x00FF);
		temp[3] = ((nFromProc) & 0x00FF);
		ret = mDequeuen(vm->mm->pcb[vm->mm->nCurrProc - 1].msgq, disasm(temp), msg);
		bLoadAny = 1;
	} else
		/* nFromProc == 'X''X' so receive from any */
		ret = mDequeue(vm->mm->pcb[vm->mm->nCurrProc - 1].msgq, msg);
	if (ret == (-1))
		return (-1);

	for (i = 0; i < 10; i++) {
		memcpy(temp, (void*) &(msg[i * 4]), 4);
		vmem_store(vm, nStartAddr + i, temp, vm->mm->nCurrProc);
	}

	/* Store the process id in the register so it can be printed by the IO process */
	if (bLoadAny)
		diss(ret, vm->mm->pcb[vm->mm->nCurrProc - 1].reg);
	else
		diss(ret, vm->mm->pcb[vm->mm->nCurrProc - 1].reg);

	return 0;
}

void PutPID(VMEMMOD* vm, u_int16_t nPID) {
	/* Store the current process ID into the register */
	diss(vm->mm->nCurrProc, vm->mm->pcb[vm->mm->nCurrProc - 1].reg);
}

int Fork(VMEMMOD* vm) {
	PCB* curpcb,* newpcb;
	int nProgSize = 0, nBaseLocation = -1;
	char strTemp[4] = { 0 };
	int i = 0;
	int nNumPageAddrs = 0;

	curpcb = &(vm->mm->pcb[vm->mm->nCurrProc - 1]);

	/* Find the size of the current program in units of pages */
	nProgSize = (disasm(curpcb->limitReg) - disasm(
			curpcb->baseReg));
	nNumPageAddrs = (nProgSize/PAGESIZE);
	if(nProgSize % PAGESIZE)
		nNumPageAddrs++;
	/* Find a spot in memory for the forked program */
#ifdef BESTFIT
	nBaseLocation = FindBestFit(vm->mm->freeDisk, nNumPageAddrs);
#elif defined(FIRSTFIT)
	nBaseLocation = FindFirstFit(vm->mm->freeDisk, nNumPageAddrs);
#endif

	/* No room for the new program so return */
	if (nBaseLocation == (-1)) {
		diss(0, curpcb->reg);
		return 0;
	}

	/* Allocate more space for another PCB */
	newpcb = malloc(sizeof(PCB));
	newpcb->reg = (char*) malloc(sizeof(char[4]));
	newpcb->stackPtr = (char*) malloc(sizeof(char[4]));
	newpcb->baseReg = (char*) malloc(sizeof(char[4]));
	newpcb->limitReg = (char*) malloc(sizeof(char[4]));
	newpcb->cFlag = vm->mm->pcb[vm->mm->nCurrProc - 1].cFlag;
	newpcb->IC = (char*) malloc(sizeof(size_t));
	newpcb->fpBrain = NULL;
	newpcb->pagetable = (PAGETABLE*) malloc(sizeof(PAGETABLE));

	/* Initialize the pagetable structure members, all page addresses are zero */
	newpcb->pagetable->pnPageAddr = (int*) calloc(nNumPageAddrs, sizeof(int));

	/* Initialize all valid bits to invalid */
	newpcb->pagetable->pchValidness = (char*) malloc(sizeof(char) * nNumPageAddrs);
	for(i = 0; i < nNumPageAddrs; i++){
		newpcb->pagetable->pchValidness[i] = INVALID;
	}

	/* Copy the pcb stuff */
	memcpy((void*) (newpcb->reg), (void*) (curpcb->reg), sizeof(char[4]));
	memcpy((void*) (newpcb->stackPtr), (void*) (curpcb->stackPtr), sizeof(char[4]));

	diss(0, newpcb->baseReg);
	diss((nProgSize), newpcb->limitReg);

	diss(disasm(curpcb->IC), newpcb->IC);

	vm->mm->pcb = (PCB*) realloc((void*) vm->mm->pcb, sizeof(PCB) * (vm->mm->nNextPID));
		if (!vm->mm->pcb) {
			printf("Failed to allocate more space for the new PCB\n");
			return (-1);
		}
		vm->mm->pcb[vm->mm->nNextPID - 1] = *newpcb;

	/* TODO: find a way to read the current program and store it into disk automatically */

	addDNode(vm->mm->usedDisk, nBaseLocation,(nBaseLocation + nNumPageAddrs), vm->mm->nNextPID);
	removeNode(vm->mm->freeDisk, nBaseLocation, (nBaseLocation + nNumPageAddrs));


	/* Copy this program into a new memory block for the new process */
	for (i = 0; i < nProgSize; i++) {
		/* We do not need the PID-1 here because it is offset in mem_read/mem_store */
		vmem_read(vm, i, strTemp, vm->mm->nCurrProc);
		vmem_store(vm, i, strTemp, vm->mm->nNextPID);
	}

	/*
	 * If completed properly then copy child process id to parent register
	 * and parent process id to child register
	 */
	if (nBaseLocation != (-1)) {
		diss(vm->mm->nNextPID, curpcb->reg);
		diss((vm->mm->nCurrProc), newpcb->reg);
		vm->mm->nNumProgs++;
		vm->mm->nNextPID++;
		return 0;
	}

	return -1;
}

int Exec(VMEMMOD* vm, char upperchar, char lowerchar) {
	PCB* curpcb = &(vm->mm->pcb[vm->mm->nCurrProc -1]);
	char strFilename[3] = { 0 };
	int nNewSize = 0, nBaseLocation = -1, err = -1, i = 0;
	int nPrevBase, nPrevLimit, basepageaddr;
	char bMove = 0;

	int nNumPages = -1, oldNumPages = 0;
	int nCurrSize = disasm(curpcb->limitReg)
			- disasm(curpcb->baseReg);

	strFilename[0] = upperchar;
	strFilename[1] = lowerchar;
	strFilename[2] = '\0';


	oldNumPages = getNumPages(vm, vm->mm->nCurrProc);
	nNewSize = FindNewSize(strFilename);

	nNumPages = nNewSize / PAGESIZE;
	if (nNewSize % PAGESIZE)
		nNumPages++;

	/* The new program will not fit in the current memory space so it needs to be moved */
	//if ((nCurrSize <= nNewSize))
	//	bMove = 1;

	DISKNODE dn;

	getPidPage(vm->mm->usedDisk, &dn, vm->mm->nCurrProc);

	nPrevBase = dn.base;
	nPrevLimit = dn.end;

	//nPrevBase = disasm(curpcb->baseReg);
	//nPrevLimit = disasm(curpcb->limitReg);


	/* If needs to be moved see if there is an available space for the program */
	addNode(vm->mm->freeDisk, nPrevBase, nPrevLimit); 			// TODO: fix nates stupid changes # 2
	//if (bMove) {
		/* Find a place to put the new program */
#ifdef BESTFIT
		nBaseLocation = FindBestFit(vm->mm->freeDisk, nNumPages);
#elif defined(FIRSTFIT)
		nBaseLocation = FindFirstFit(vm->mm->freeDisk, nNumPages);
#endif
	//} else
		//nBaseLocation = disasm(curpcb->baseReg);

	/* There is no room for the new program */
	if (nBaseLocation == -1) {
		removeNode(vm->mm->freeDisk, nBaseLocation, nBaseLocation + nNumPages);
		diss(1, curpcb->reg);
		return -1;
	}

	//TODO: change this to deal with disk instead of RAM.

	/* Clear the current program from memory */
	removeDNode(vm->mm->usedDisk,vm->mm->nCurrProc);
	//addDNode(vm->mm->usedDisk, nBaseLocation, nBaseLocation + nNumPages, vm->mm->nCurrProc);

	for (i = nPrevBase; i < nPrevLimit; i++) {
		memset((void*) &(vm->mm->diskBlock[i][0]), '\0', 4 * sizeof(char)* PAGESIZE);
	}


	/* Set IC and base register to the new locations */
	diss(0, curpcb->baseReg);
	diss(0, curpcb->IC);

	/* Close the previous BRAIN file before opening a new one...diss */
	if(curpcb->fpBrain){
		fclose(curpcb->fpBrain);
		curpcb->fpBrain = NULL;
	}

/* Load the new program at the base memory location */
	err = load_brain(vm->mm, strFilename, &(curpcb->fpBrain),
			nBaseLocation, vm->mm->nCurrProc);

	/* Deallocate the space used by the previous program DONE before that other stuff (ROB) */
		for (i = 0; i < oldNumPages; i++) {
			basepageaddr = curpcb->pagetable->pnPageAddr[i]/PAGESIZE;
			if (curpcb->pagetable->pchValidness[i]>0) {
				addNode(vm->mm->freeMem, basepageaddr, basepageaddr);
			}
		}

	/* Free the previous page table and then allocate a new one makes it easier not more efficient */
	free(curpcb->pagetable->pnPageAddr);
	free(curpcb->pagetable->pchValidness);
	free(curpcb->pagetable);

	/* Allocate a new page table.. again */
	curpcb->pagetable = (PAGETABLE*) malloc(sizeof(PAGETABLE));

	/* Initialize the pagetable structure members, all page addresses are zero */
	curpcb->pagetable->pnPageAddr = (int*) calloc(nNumPages, sizeof(int));

	/* Initialize all valid bits to invalid */
	curpcb->pagetable->pchValidness = (char*) malloc(sizeof(char) * nNumPages);
	for(i = 0; i < nNumPages; i++){
		curpcb->pagetable->pchValidness[i] = INVALID;
	}

	if (err == (-1)) {
		printf("load_brain failed in exec.\n");
		removeNode(vm->mm->freeMem, nPrevBase, nPrevLimit);				// TODO: fix nate's stupid changes
		return (-1);
	}

	mQueueInit(&(curpcb->msgq));
	/* Store the return value in the register */
	diss(0, curpcb->reg);

	return 0;
}

void LoadShared(VMEMMOD* vm, size_t location) {
	load_share(vm->mm->shared, location, vm->mm->pcb[vm->mm->nCurrProc - 1].reg);
}

void StoreShared(VMEMMOD* vm, size_t location) {
	store_share(vm->mm->shared, location, vm->mm->pcb[vm->mm->nCurrProc - 1].reg);
}

int P(VMEMMOD* vm, size_t index) {
	return _p(vm->mm->shared, index, vm->mm->nCurrProc);
}

int V(VMEMMOD* vm, size_t index) {
	return _v(vm->mm->shared, index);
}

void SemaphoreInit(VMEMMOD* vm, size_t index) {
	sema_init(vm->mm->shared, index, disasm(vm->mm->pcb[vm->mm->nCurrProc - 1].reg));
}

/* Helper Functions */
size_t atob(bop op1, bop op2) {
	size_t retval = -1;
	if (op1 != 0 && op2 != 0) {
		char a[3];
		a[0] = op1;
		a[1] = op2;
		a[2] = '\0';
		retval = atoi(a);
	}
	return retval;
}

/* diss:  convert n to characters in s */
void itob(int n, char * s) {
	int i;
	i = -1;
	do { /* generate digits in reverse order */
		i = i + 1;
		s[i] = n % 10 + '0'; /* get next digit */
	} while ((n /= 10) > 0); /* delete it */
}

